package com.ironman.compute.wrapper;

import com.ironman.common.params.*;
import com.ironman.common.threadpool.ThreadPool;
import com.ironman.common.util.AccuracyUtil;
import com.ironman.compute.*;
import com.ironman.compute.consumer.*;
import com.ironman.compute.context.SailingShareContext;
import com.ironman.compute.properties.SailingStandardProperties;
import com.ironman.event.properties.SysTrainingProperties;
import lombok.extern.slf4j.Slf4j;
import org.dromara.mica.mqtt.core.client.MqttClient;

/**
 * 航向分析包装器
 */
@Slf4j
public class SailingComputerWrapper {

    /**
     * 训练艇运动员信息
     */
    private final SysTrainingProperties sysTrainingProperties;

    /**
     * 环境风
     */
    private final WindComputer windComputer;

    /**
     * 航行分析共享上下文
     */
    private final SailingShareContext sailingShareContext;

    /**
     * GPS
     */
    private final GpsEmptyComputer gpsEmptyComputer;

    /**
     * 船速
     */
    private final SpeedAverageComputer speedComputer;

    /**
     * 航向
     */
    private final HeadingVectorComputer headingComputer;

    /**
     * 船首向
     */
    private final YawVectorComputer yawComputer;

    /**
     * 平衡
     */
    private final RolAverageComputer rolComputer;

    /**
     * 心率-主舵手
     */
    private final HeartbeatAverageComputer mHeartbeatComputer;

    /**
     * 心率-副舵手
     */
    private final HeartbeatAverageComputer sHeartbeatComputer;

    private final GpsConsumer gpsConsumer;

    private final SpeedAndVmgAndWindConsumer speedAndVmgAndWindConsumer;

    private final HeadingConsumer headingConsumer;

    private final HeartrateConsumer heartrateConsumer0;

    private final HeartrateConsumer heartrateConsumer1;

    private final RolConsumer rolConsumer;

    private final YawConsumer yawConsumer;

    public SailingComputerWrapper(SysTrainingProperties sysTrainingProperties,
                                  SailingStandardProperties sailingStandardProperties,
                                  SailingParamWrapper sailingParamWrapper,
                                  MqttClient mqttClient) {
        this.sysTrainingProperties = sysTrainingProperties;

        this.sailingShareContext = new SailingShareContext(sailingStandardProperties);

        HeadingParam headingParam = sailingParamWrapper.getHeadingParam();
        SpeedParam speedParam = sailingParamWrapper.getSpeedParam();
        RolParam rolParam = sailingParamWrapper.getRolParam();
        YawParam yawParam = sailingParamWrapper.getYawParam();
        HeartrateParam heartrateParam = sailingParamWrapper.getHeartrateParam();

        this.windComputer = new WindComputer(sysTrainingProperties.getFollowTrainingBoatCode());

        this.gpsEmptyComputer = new GpsEmptyComputer();

        this.speedComputer = new SpeedAverageComputer(speedParam.getWindowSize());
        this.headingComputer = new HeadingVectorComputer(headingParam.getWindowSize());
        this.yawComputer = new YawVectorComputer(yawParam.getWindowSize());
        this.rolComputer = new RolAverageComputer(rolParam.getWindowSize());
        this.mHeartbeatComputer = new HeartbeatAverageComputer(heartrateParam.getWindowSize());
        this.sHeartbeatComputer = new HeartbeatAverageComputer(heartrateParam.getWindowSize());

        this.gpsConsumer = new GpsConsumer(sysTrainingProperties, mqttClient);

        this.headingConsumer = new HeadingConsumer(headingParam, sysTrainingProperties, mqttClient);
        this.speedAndVmgAndWindConsumer = new SpeedAndVmgAndWindConsumer(speedParam, sysTrainingProperties, mqttClient);
        this.rolConsumer = new RolConsumer(rolParam, sysTrainingProperties, mqttClient);
        this.yawConsumer = new YawConsumer(yawParam, sysTrainingProperties, mqttClient);
        this.heartrateConsumer0 = new HeartrateConsumer(heartrateParam, sysTrainingProperties, mqttClient);
        this.heartrateConsumer1 = new HeartrateConsumer(heartrateParam, sysTrainingProperties, mqttClient);
    }

    public void doCompute() {
        ThreadPool.FIXED_EXECUTOR.submit(() -> windComputer.init((trainingBoatCode, declination, windSpeed, windDirection, customSpeed, customDirection, ts) -> {
            log.debug("风数据=>教练艇编号{}，风速{}cm/s，风向{}°，自定义风速{}cm/s，自定义风向{}°,时间{}", trainingBoatCode, windSpeed, windDirection, customSpeed, customDirection, ts);
            sailingShareContext.updateWind(trainingBoatCode, declination, windSpeed, windDirection, customSpeed, customDirection, ts);
        }));

        ThreadPool.FIXED_EXECUTOR.submit(() -> gpsEmptyComputer.init((recentGps) -> {
            log.debug("GPS数据=>GPS轨迹{}", recentGps);
            sailingShareContext.updateGps(sysTrainingProperties.getMHmName(), sysTrainingProperties.getColor(), recentGps, gpsConsumer);
        }));

        ThreadPool.FIXED_EXECUTOR.submit(() -> speedComputer.init((ts, average) -> {
            log.debug("船速数据=>{}，当前平均船速{}cm/s", ts, AccuracyUtil.halfUpSpeedDouble(average));
            sailingShareContext.updateSpeed(average, speedAndVmgAndWindConsumer);
        }));

        ThreadPool.FIXED_EXECUTOR.submit(() -> headingComputer.init((ts, average) -> {
            log.debug("航向数据=>{}，当前平均航向{}°", ts, AccuracyUtil.downDirectionInteger(average));
            sailingShareContext.updateHeading(average, headingConsumer);
        }));

        ThreadPool.FIXED_EXECUTOR.submit(() -> yawComputer.init((ts, average) -> {
            log.debug("船首向数据=>{}，当前平均航首向{}°", ts, AccuracyUtil.downDirectionInteger(average));
            sailingShareContext.updateYaw(average, yawConsumer);
        }));

        ThreadPool.FIXED_EXECUTOR.submit(() -> rolComputer.init((ts, average) -> {
            log.debug("平衡数据=>{}，当前平均横滚角{}°", ts, AccuracyUtil.downDirectionInteger(average));
            sailingShareContext.updateRol(average, rolConsumer);
        }));

        ThreadPool.FIXED_EXECUTOR.submit(() -> mHeartbeatComputer.init(0, (ts, average) -> {
            log.debug("心率数据=>主舵手: {} 当前平均心率{}bpm", ts, average);
            sailingShareContext.updateMHeartrate(average, heartrateConsumer0);
        }));

        ThreadPool.FIXED_EXECUTOR.submit(() -> sHeartbeatComputer.init(1, (preAverage, average) -> {
            log.debug("心率数据=>副舵手: 前平均心率{}bpm，当前平均心率{}bpm", preAverage, average);
            sailingShareContext.updateSHeartrate(average, heartrateConsumer1);
        }));
    }
}
